﻿using System;
using System.Collections.Generic;
using System.Linq;
using Common.Extension;
using Common.Model;
using Common.Util;
using HotTopic.collector;

namespace HotTopic.service
{
    class TopicMergeService
    {
        public const float Similarity = 0.5f;
        private DateTime _time = DateTime.Now;
//        static void Main(string[] args)
//        {
//            TopicMergeService topicMergeService = new TopicMergeService();
//            topicMergeService.MergeSoftwareTopics();
//            Console.ReadKey();
//        }

        //合并本地软件提取出来的主题
        public Dictionary<string, Topic> MergeSoftwareTopics()
        {
            
            _time = DateTime.Now;
            
            TdxCollector tdxCollector = new TdxCollector();
            DzhCollector dzhCollector = new DzhCollector();
            ThsCollector thsCollector = new ThsCollector();
            
            //以通达信概念为基准
            Dictionary<string, List<string>> tdxTopics = tdxCollector.GetTopics();
            Dictionary<string, List<string>> dzhTopics = dzhCollector.GetTopics();
            Dictionary<string, List<string>> thsTopics = thsCollector.GetTopics();
            
            //预处理的主题
            Dictionary<string,Topic> tdxTopicDic = getTopicDic(tdxTopics);
            Dictionary<string,Topic> dzhTopicDic = getTopicDic(dzhTopics);
            Dictionary<string,Topic> thsTopicDic = getTopicDic(thsTopics);


            //获取大智慧与同花顺历史集合
            Dictionary<string, Topic> dzhTopicsHis = TopicNameRedisDbProvider.ListHisTopics(Constant.dzhname);
            Dictionary<string, Topic> thsTopicsHis = TopicNameRedisDbProvider.ListHisTopics(Constant.thsname);

            //保存历史主题
            TopicNameRedisDbProvider.CacheHisTopics(Constant.tdxname,tdxTopicDic);
            TopicNameRedisDbProvider.CacheHisTopics(Constant.dzhname,dzhTopicDic);
            TopicNameRedisDbProvider.CacheHisTopics(Constant.thsname,thsTopicDic);

            //合并主板和通达信板块
            Dictionary<string, Topic> mainTopics = ProcessTdxTopicSet(tdxTopicDic);

            //获取新增的软件板块
            var dzhNewTopicsDic = dzhTopicDic.Where(dict => !dzhTopicsHis.ContainsKey(dict.Key)).ToDictionary(v=>v.Key,v=>v.Value);
            var thsNewTopicsDic = thsTopicDic.Where(dict => !thsTopicsHis.ContainsKey(dict.Key)).ToDictionary(v=>v.Key,v=>v.Value);

            //处理大智慧与同花顺新增板块
            Dictionary<string, Topic> newTopics = ProcessNewTopics( dzhNewTopicsDic, thsNewTopicsDic);
            
            //合并主板与大智慧同名板块
            ProcessThsSameName2MainTopics(mainTopics, dzhTopicDic);
            //合并主板与同花顺同名板块
            ProcessThsSameName2MainTopics(mainTopics, thsTopicDic);
            
            //合并主板与新增板块
            ProcessNewTopics2MainTopics(mainTopics, newTopics);
            
            ProcessMainTopicManul(mainTopics);
            
            ProcessMainTopicStocksManul(mainTopics);
            
            //存储主板
            TopicNameRedisDbProvider.CacheMainTopic(mainTopics);
            
            foreach (var topic in mainTopics.Values)
            {
                foreach (var stock in topic.Stocks)
                {
                    stock.TopicName = topic.TopicName;
                }
            }
            
            return mainTopics;
        }

        //人工处理股票
        private void ProcessMainTopicStocksManul(Dictionary<string, Topic> mainTopics)
        {

            foreach (var topicName in mainTopics.Keys)
            {
                var listTopicStocksAdd = TopicNameRedisDbProvider.ListTopicStocksAdd(topicName);
                var stocks = new HashSet<Stock>();
                foreach (var stockCode in listTopicStocksAdd)
                {
                    var stock = new Stock
                    {
                        StockCode = stockCode,
                        InsertDate = Util.GetTimeStamp(_time)
                    };
                    stocks.Add(stock);
                }
                mainTopics.Get(topicName).Stocks.UnionWith(stocks);

                var listDropStocks = TopicNameRedisDbProvider.ListDropStocks(topicName);
                
                stocks.Clear();
                foreach (var stockCode in listTopicStocksAdd)
                {
                    var stock = new Stock
                    {
                        StockCode =  stockCode
                    };
                    stocks.Add(stock);
                }
                mainTopics.Get(topicName).Stocks.ExceptWith(stocks);
            }
        }

        //人工处理板块
        private void ProcessMainTopicManul(Dictionary<string, Topic> mainTopics)
        {
            var listTopicDrop = TopicNameRedisDbProvider.ListTopicDrop();
            foreach (var topicName in listTopicDrop.Keys)
            {
                mainTopics.Remove(topicName);
            }

            var listTopicAdd = TopicNameRedisDbProvider.ListTopicAdd();
            mainTopics.AddRange(listTopicAdd, false);
        }

        //合并主板与新增板块
        private void ProcessNewTopics2MainTopics(Dictionary<string, Topic> mainTopics, Dictionary<string, Topic> newTopics)
        {
            //合并重名板块
            foreach (var topicName in mainTopics.Keys)
            {
                if(newTopics.ContainsKey(topicName))
                {
                    var mainTopic = mainTopics.Get(topicName);
                    var softTopic = newTopics.Get(topicName);
                    var newStocks = softTopic.Stocks.Except(mainTopic.Stocks.Intersect(softTopic.Stocks)).ToList();
                    foreach (var newStock in newStocks)
                    {
                        newStock.InsertDate = Util.GetTimeStamp(_time);
                    }
                    TopicNameRedisDbProvider.CacheUnProcessNewStocks(topicName,new HashSet<Stock>(newStocks));
                    mainTopic.Stocks.UnionWith(newStocks);
                }
                newTopics.Remove(topicName);
            }
            
            //新增板块处理相似度问题
            var simliarityTopicSet = new HashSet<string>();
            var simliarityTopicSetKey = new HashSet<string>();

            var mainTopicNameList = mainTopics.Keys.ToList();
            var newTopicNameList = newTopics.Keys.ToList();

            var nonjoinderTopics = TopicNameRedisDbProvider.ListNonjoinderTopics();
            var joinderTopics = TopicNameRedisDbProvider.ListJoinderTopics();

            for (int i = 0; i < newTopicNameList.Count; i++)
            {
                var left = newTopicNameList[i];
                
                for (int j = i; j < mainTopicNameList.Count; j++)
                {
                    var right = mainTopicNameList[j];
                    
                    if (simliarityTopicSet.Contains(left) || simliarityTopicSet.Contains(right))
                    {
                        continue;
                    }
                    
                    var key = Util.GetJoinKey(left, right);
                    var calcSimilarity = Util.CalcSimilarity(mainTopics.Get(right).Stocks,newTopics.Get(left).Stocks);

                    if ((!(calcSimilarity > Similarity) && !joinderTopics.Contains(key)) ||
                        nonjoinderTopics.Contains(key))
                    {
                        continue;
                    } 
                      
                    simliarityTopicSet.Add(left);
                    simliarityTopicSet.Add(right);
                    simliarityTopicSetKey.Add(left);
                        
                    var processSimliarityTopic = ProcessSimliarityTopic(right, mainTopics.Get(right), left, newTopics.Get(left), right);
                    
                    mainTopics.Remove(right);
                    mainTopics.Add(right,processSimliarityTopic);
                    newTopics.Remove(left);
                }
            }
            
            TopicNameRedisDbProvider.CacheJoinderTopic(simliarityTopicSet);
            
            //合并非相似板块
            foreach (var topicName in newTopics.Keys.Except(simliarityTopicSet).ToList())
            {
                mainTopics.Add(topicName, newTopics.Get(topicName));
            }
        }

        //合并主板与软件同名板块
        private void ProcessThsSameName2MainTopics(Dictionary<string, Topic> mainTopics, Dictionary<string, Topic> softTopics)
        {
            foreach (var topicName in mainTopics.Keys)
            {
                if(softTopics.ContainsKey(topicName))
                {
                    var mainTopic = mainTopics.Get(topicName);
                    var softTopic = softTopics.Get(topicName);
                    var newStocks = softTopic.Stocks.Except(mainTopic.Stocks.Intersect(softTopic.Stocks)).ToList();

                    newStocks.ForEach(stock => stock.InsertDate = Util.GetTimeStamp(_time));

                    TopicNameRedisDbProvider.CacheUnProcessNewStocks(topicName,new HashSet<Stock>(newStocks));
                    mainTopic.Stocks.UnionWith(newStocks);
                }
            }
        }

        private Dictionary<string, Topic> ProcessNewTopics(Dictionary<string, Topic> dzhNewTopicsDic,Dictionary<string, Topic> thsNewTopicsDic)
        {
            //新增板块插入新增时间和来源
            foreach (var topicName in dzhNewTopicsDic.Keys)
            {
                var topic = new Topic
                {
                    TopicName = topicName,
                    InsertDate = Util.GetTimeStamp(_time),
                    From = Constant.dzhname
                };
            }

            foreach (var topicName in thsNewTopicsDic.Keys)
            {
                var topic = new Topic
                {
                    TopicName = topicName,
                    InsertDate = Util.GetTimeStamp(_time),
                    From = Constant.thsname
                };
            }

            //保存新增板块
            TopicNameRedisDbProvider.CacheNewTopic(dzhNewTopicsDic);
            TopicNameRedisDbProvider.CacheNewTopic(thsNewTopicsDic);
            
            //处理新增板块的重名与相似度问题
            var newTopics = dzhNewTopicsDic.Keys.Union(thsNewTopicsDic.Keys).ToList();

            var topics = new Dictionary<string, Topic>();
            
            //新增板块处理同名
            foreach (var newTopicName in newTopics)
            {
                if (dzhNewTopicsDic.ContainsKey(newTopicName) && thsNewTopicsDic.ContainsKey(newTopicName))
                {
                    var dzhTopic = dzhNewTopicsDic.Get(newTopicName);
                    var thsTopic = thsNewTopicsDic.Get(newTopicName);
                    dzhTopic.Stocks.UnionWith(thsTopic.Stocks);
                    thsTopic.Stocks = dzhTopic.Stocks;
                    string from = Constant.dzhname + ":" + Constant.thsname;
                    dzhTopic.From = from;
                    thsTopic.From = from;
                    topics.Add(newTopicName, dzhTopic);
                    
                    dzhNewTopicsDic.Remove(newTopicName);
                    thsNewTopicsDic.Remove(newTopicName);
                }
            }
            
            //新增板块处理相似度问题
            var simliarityTopicSet = new HashSet<string>();
            var simliarityTopicSetKey = new HashSet<string>();

            var nonjoinderTopics = TopicNameRedisDbProvider.ListNonjoinderTopics();
            var joinderTopics = TopicNameRedisDbProvider.ListJoinderTopics();

            var dzhList = dzhNewTopicsDic.Keys.ToList();
            var thsList = thsNewTopicsDic.Keys.ToList();
            
            for (var i = 0; i < dzhList.Count; i++)
            {
                var left = dzhList[i];
                
                for (var j = i; j < thsList.Count; j++)
                {
                    var right = thsList[j];

                    if (simliarityTopicSet.Contains(left) || simliarityTopicSet.Contains(right))
                    {
                        continue;
                    }

                    var key = Util.GetJoinKey(left, right);
                    var calcSimilarity = Util.CalcSimilarity(dzhNewTopicsDic.Get(left).Stocks,
                        thsNewTopicsDic.Get(right).Stocks);

                    if ((!(calcSimilarity > Similarity) && !joinderTopics.Contains(key)) ||
                        nonjoinderTopics.Contains(key))
                    {
                        continue;
                    }
                        
                    simliarityTopicSet.Add(left);
                    simliarityTopicSet.Add(right);
                    simliarityTopicSetKey.Add(left);
                    
                    var processSimliarityTopic = ProcessSimliarityTopic(left, dzhNewTopicsDic.Get(left), right,
                        thsNewTopicsDic.Get(right), null);
                    topics.Add(key, processSimliarityTopic);
                    
                    dzhNewTopicsDic.Remove(left);
                    thsNewTopicsDic.Remove(right);
                }
            }
            
            TopicNameRedisDbProvider.CacheJoinderTopic(simliarityTopicSetKey);
            
            //剩余板块
            topics.AddRange(dzhNewTopicsDic, false);
            topics.AddRange(dzhNewTopicsDic, false);
            
            return topics;
        }

        private Topic ProcessSimliarityTopic(string left, Topic leftTopic, string right, Topic rightTopic,string cacheKey)
        {
            var topic = new Topic
            {
                TopicName = leftTopic.TopicName,
                From = Constant.dzhname + Constant.thsname,
                InsertDate = leftTopic.InsertDate,
                MergeName = leftTopic.MergeName,
                Stocks = leftTopic.Stocks
            };

            var joinKey = Util.GetJoinKey(left,right);
            if (null == cacheKey)
            {
                cacheKey = joinKey;
            }
            
            TopicNameRedisDbProvider.CacheJoinderTopic(cacheKey);
            leftTopic.MergeName = rightTopic.MergeName = cacheKey;
            
            var insert = leftTopic.Stocks.Intersect(rightTopic.Stocks).ToList();

            var unProcess = leftTopic.Stocks.Except(insert).Union(rightTopic.Stocks.Except(insert)).ToList();

            TopicNameRedisDbProvider.CacheUnProcessNewStocks(cacheKey, new HashSet<Stock>(unProcess));

            var hashSet = new HashSet<Stock>();

            leftTopic.Stocks = hashSet;
            
            hashSet.UnionWith(leftTopic.Stocks.Union(rightTopic.Stocks));
            leftTopic.Stocks = hashSet;
            rightTopic.Stocks = hashSet;
            
            topic.Stocks = hashSet;
            topic.MergeName = joinKey;
            if (null == cacheKey)
            {
                topic.TopicName = joinKey.Split(new char[]{
                    ':'
                })[0];
            }
            else
            {
                topic.TopicName = cacheKey;
            }
            return topic;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dic"></param>
        /// <returns>主题名=>topic</returns>
        private Dictionary<string,Topic> getTopicDic(Dictionary<string, List<string>> dic)
        {
            var dictionary = new Dictionary<string,Topic>();
            foreach (var pair in dic)
            {
                var stocks = new HashSet<Stock>();
                var topic = new Topic
                {
                    TopicName = pair.Key,
                    Stocks = stocks
                };
                foreach (var stockCode in pair.Value)
                {
                    var stock = new Stock
                    {
                        StockCode = stockCode
                    };
                    stocks.Add(stock);
                }
                dictionary.Add(pair.Key, topic);
            }
            return dictionary;
        }

        //预处理通达信概念板块
        private Dictionary<string,Topic> ProcessTdxTopicSet(Dictionary<string,Topic> tdxTopicSet)
        {
            var main = new Dictionary<string, Topic>();

            var listTdxTopicDrop = TopicNameRedisDbProvider.ListTopicDrop();
            
            var listTopicMain = TopicNameRedisDbProvider.ListTopicMain();

            var listNewTopic = TopicNameRedisDbProvider.ListNewTopic();
            //去除不需要的板块
            foreach (var topicName in listTdxTopicDrop.Keys)
            {
                tdxTopicSet.Remove(topicName);
            }

            var topicsNameList = listTopicMain.Keys.Union(tdxTopicSet.Keys);
            
            //合并主板与通达信概念板块
            foreach (string topicName in topicsNameList)
            {
                if(tdxTopicSet.ContainsKey(topicName) && listTopicMain.ContainsKey(topicName))
                {
                    var topicTdx = tdxTopicSet.Get(topicName);
                    var topicMain = listTopicMain.Get(topicName);
                    foreach (var stock in topicTdx.Stocks.Except(topicMain.Stocks))
                    {
                        stock.InsertDate = Util.GetTimeStamp(_time);
                    }
                    //主板主题股票列表合并通达信主题股票列表
                    topicMain.Stocks.UnionWith(topicTdx.Stocks);
                    main.Add(topicName,topicMain);
                }
                else if(tdxTopicSet.ContainsKey(topicName))
                {
                    var topicTdx = tdxTopicSet.Get(topicName);
                    topicTdx.InsertDate = Util.GetTimeStamp(_time);
                    foreach (var stock in topicTdx.Stocks)
                    {
                        stock.InsertDate = Util.GetTimeStamp(_time);
                    }
                    main.Add(topicName, topicTdx);
                }
                else
                {
                    main.Add(topicName, listTopicMain.Get(topicName));
                }
            }

            return main;

        }
        
    }
}